In This Part
by K. David White
In This Chapter
Character manipulation and managing data in lists and sets have been among the staples of software development since the beginning of computerdom. In fact, most of you have probably grown weary of the Hello World program in all its varied forms. It seems as if you cant pick up a beginners programming book, in any language, without finding it.
I dont have the heart to do that to you, and because this is not a beginners book, youve probably been through it. You might have even used CString in some fashion, or one of the templated list classes that MFC provides. In this chapter, you will take a closer look at what MFC gives you as far as managing strings, lists, sets, and maps.
Without going into much detail, I will also introduce you to the Standard Template Library (STL) functions that you might end up using in place of the MFC classes. Remember, you may be asked to develop COM objects without using the MFC DLLs. Understanding what MFC gives you, and then taking a look at other alternatives, only helps to expand your capabilities.
In Fortran, you were introduced to the concept of a string in all its formatted glory. If you havent programmed in Fortran, you havent lived! In C, you were introduced to character strings. These were treated differently, even though they did the same thing. In fact, a big part of your learning experience with C was learning to deal with character pointers. I dont have a fond memory of those days, only the day that it finally sunk in and the world opened up! (Well, almost!)
C++, with the object-oriented approach, still makes use of character strings, but people started encapsulating string functions into string classes that could be used easily. Well, MFC does the same thing. The CString class encapsulates character string functionality to make string manipulation a breeze.
The CString class is defined in the MFC header file AFX.H. If you look inside this file for the CString declaration, you will notice that it goes on for quite a few pages. The main element, though, is the buffer that CString encapsulates, as you see in Listing 20.1.
Listing 20.1 The CString Protected Data Member (AFX.H)
protected:
LPTSTR m_pchData; // pointer to ref counted string data
Listing 20.1 shows the only data member of CString, m_pchData. It makes sense! CString encapsulates a single string, or character buffer. The LPTSTR is defined as a 32-bit pointer to a character string. Now that you know CString contains a string pointer, you probably have questions about memory allocation and reallocation and where that buffer is actually kept. Are you ready to look at some MFC code to solve this mystery?
Notice the comment in Listing 20.1, // pointer to ref counted string data. This is a pointer to a reference-counted string. What exactly does it mean to have reference counting on a string? To solve the problem of memory leaks, and having copies of strings floating around that are no longer used, MFC implements a form of reference counting to verify that no unnecessary copies of the buffer are hanging around. If youve read my COM chapter (Chapter 10), you understand the concept of reference counting. Notice in Listing 20.2, which is an expanded listing of the CString declaration, that you dont have anything to store the reference count.
Listing 20.2 The Expanded CString Declaration (AFX.H)
// Implementation
public:
~CString();
int GetAllocLength() const;
protected:
LPTSTR m_pchData; // pointer to ref counted string data
// implementation helpers
CStringData* GetData() const;
void Init();
void AllocCopy(CString& dest, int nCopyLen,
Äint nCopyIndex, int nExtraLen) const;
void AllocBuffer(int nLen);
void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData);
void ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,
Äint nSrc2Len, LPCTSTR lpszSrc2Data);
void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData);
void CopyBeforeWrite();
void AllocBeforeWrite(int nLen);
void Release();
static void PASCAL Release(CStringData* pData);
static int PASCAL SafeStrlen(LPCTSTR lpsz);
static void FASTCALL FreeData(CStringData* pData);
You will notice that many functions are defined that appear to do the reference counting for the CString buffer, but it still doesnt have a reference count holder. Notice the line CStringData* GetData() const;. This declaration is a clue! Back to AFX.H. Listing 20.3 shows you that the CStringData structure contains the reference count and string information important to the other CString functions. You will also noti that MFC used to store the data buffer here as well.
Listing 20.3 The CStringData Structure (AFX.H)
struct CStringData
{
long nRefs; // reference count
int nDataLength; // length of data (including terminator)
int nAllocLength; // length of allocation
// TCHAR data[nAllocLength]
TCHAR* data() // TCHAR* to managed data
{ return (TCHAR*)(this+1); }
};
String Allocation
The CString class uses the AllocBuffer member helper function to allocate and manage the memory during the construction phase. Listing 20.4 is the source code for the buffer allocation logic. Notice the comment starting at the second line, // always allocate one extra character for \0 termination. This allocation will automatically add the null terminator, so remember to send the actual length of the string that you need to create. If the length passed is zero, which is the case during a declaration without assignment, this routine will call the Init() routine to reserve some space. Okay, what are the following lines doing?
pData = (CStringData*)
new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)];
pData->nAllocLength = nLen;